package com.xzh.springCloud.controller;


import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.xzh.springCloud.entity.Member;
import com.xzh.springCloud.entity.Result;
import com.xzh.springCloud.handler.CustomGlobalFallback;
import com.xzh.springCloud.service.MemberService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.List;

/**
 * @Author: zhiHong
 * @CreateTime: 2023-08-24 17:29
 * @Description: member的controller类
 */
@Slf4j
@RestController
public class MemberController {
    // 装配 MemberService
    @Resource
    private MemberService memberService;

    // 装配 DiscoveryClient
    @Resource
    private DiscoveryClient discoveryClient;

    /**
     * 1. @SentinelResource: 指定 sentinel 限流资源
     * 2. value = "news" 表示 sentinel 限流资源名称，由程序员指定
     * 3. blockHandler = "newsBlockHandler" 表示触发限流后交给谁进行处理
     */
    @GetMapping("/news")
    @SentinelResource(value = "news", blockHandler = "newsBlockHandler")
    public Result queryNews(@RequestParam(value = "id", required = false) String id,
                            @RequestParam(value = "type", required = false) String type) {
        // 在实际开发中，新闻应该到 DB 或者缓存中获取
        log.info("到 DB 查询新闻");
        return Result.success("返回 id = " + id + " 新闻 from DB");
    }


    // 热点 key 限制
    public Result newsBlockHandler(String id, String type, BlockException blockException) {
        return Result.success("查询 id = " + id, "的新闻触发 key 热点保护，sorry…");
    }

    @GetMapping("/member/consumer/discovery")
    public Object discovery() {
        List<String> services = discoveryClient.getServices();  // 得到注册中心中服务名
        for (String service : services) {
            log.info("=================================================");
            log.info("服务名 = {}", service);
            List<ServiceInstance> instances = discoveryClient.getInstances(service);    // 根据 service 名得到拥有实例
            log.info("-------------------------------------------------");
            for (ServiceInstance instance : instances) {
                log.info("id = {}, host = {}, port = {}, uri = {}", instance.getInstanceId(), instance.getHost(), instance.getPort(), instance.getUri());
            }
            log.info("-------------------------------------------------");
            log.info("=================================================");
        }

        return discoveryClient;
    }


    /**
     * 这里需要注意：如果前端使用的 json 格式发送请求，那么需要我们使用 @RequestBody
     * 如果使用的是 form 表单形式提交，那么则不需要使用 @RequestBody
     */
    @PostMapping("/member/save")
    public Result saveMember(@RequestBody Member member) {
        int i = memberService.saveMember(member);
        if(i > 0) {
            return Result.success("添加会员成功", i);
        } else {
            return Result.error("401", "添加会员失败");
        }
    }

    /**
     * 根据 id 查询 member 相关信息
     */
    @GetMapping(value = "/member/get/{id}")
    public Result queryMemberById(@PathVariable("id") Long id) {
        Member member = memberService.queryMemberById(id);
        if(member != null) {
            return Result.success("查询成功member-service-nacos-provider-10004", member);
        } else {
            return Result.error("404", "id = " + id + "不存在");
        }
    }

    /**
     * fallbackClass 指定 fallback 异常处理类
     * fallback 指定 fallback 异常处理方法
     */
    @GetMapping("/t1")
    @SentinelResource(value = "t1", fallbackClass = CustomGlobalFallback.class, fallback = "fallbackHandlerMethod01", exceptionsToIgnore = {RuntimeException.class})
    public Result t1() {
        return null;
    }
}
